﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using OfficeOpenXml;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;

namespace KgUtils.IO
{
    public static class ExcelHelper
    {
        /// <summary>
        /// Charge les données du fichier Excel dans un tableau, détermine automatiquement si le fichier est un Excel 2007 ou Excel 2003
        /// </summary>
        /// <param name="pFilename">Le chemin et le nom du fichier à ouvrir</param>
        /// <param name="pStartRow">La ligne à partir de laquelle on veut exporter les données. Par défaut, la première ligne contenant des données (index 1ère ligne = 1).</param>
        /// <param name="pColumnsToRead">La liste des colonnes dont on veut extraire les données. Par défaut, toutes les colonnes (index 1ère colonne = 1.</param>
        /// <returns>Un tableau contenant les données du fichier sous forme de [lignes, colonnes]</returns>
        public static string[,] ReadFileData(string pFilename, int? pStartRow = null, int[] pColumnsToRead = null)
        {
            if (Path.GetExtension(pFilename) == ".xlsx")
                return ReadXLSXFileData(pFilename, pStartRow, pColumnsToRead);
            else
                return ReadXLSFileData(pFilename, pStartRow, pColumnsToRead);
        }

        /// <summary>
        /// Ecrit les données dans un fichier Excel 2003 ou 2007 (en fonction de l'extension).
        /// L'écriture Excel 2003 n'est actuellement pas supportée.
        /// </summary>
        /// <param name="pFilename">Le chemin et le nom du fichier à créer</param>
        /// <param name="pData">Un tableau contenant les données du fichier sous forme de [lignes, colonnes]</param>
        public static void WriteFileData(string pFilename, string[,] pData)
        {
            if (Path.GetExtension(pFilename) == ".xlsx")
                WriteXLSXFileData(pFilename, pData);
            else
                throw new NotSupportedException("Export en XLS non supporté.");
        }

        /// <summary>
        /// Charge les données du fichier Excel 2007 (XML) dans un tableau
        /// </summary>
        /// <param name="pFilename">Le chemin et le nom du fichier à ouvrir</param>
        /// <param name="pStartRow">La ligne à partir de laquelle on veut exporter les données. Par défaut, la première ligne contenant des données (index 1ère ligne = 1).</param>
        /// <param name="pColumnsToRead">La liste des colonnes dont on veut extraire les données. Par défaut, toutes les colonnes (index 1ère colonne = 1.</param>
        /// <returns>Un tableau contenant les données du fichier sous forme de [lignes, colonnes]</returns>
        private static string[,] ReadXLSXFileData(string pFilename, int? pStartRow = null, int[] pColumnsToRead = null)
        {
            FileInfo fi = new FileInfo(pFilename);

            using (ExcelPackage xlPackage = new ExcelPackage(fi))
            {
                // get the first worksheet in the workbook
                ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets[1];

                //get dimensions & default values:
                var maxCell = worksheet.Dimension.End;
                var minCell = worksheet.Dimension.Start;
                pStartRow = pStartRow ?? minCell.Row;
                pColumnsToRead = pColumnsToRead ?? Enumerable.Range(minCell.Column, maxCell.Column - minCell.Column + 1).ToArray();

                //check dimensions
                if (pStartRow < minCell.Row || pStartRow > maxCell.Row || pColumnsToRead.Min() < minCell.Column || pColumnsToRead.Max() > maxCell.Column)
                    throw new ArgumentOutOfRangeException("");

                var excelFileValues = new string[maxCell.Row - pStartRow.Value + 1, pColumnsToRead.Length];

                int rowCount = 0;
                for (int row = pStartRow.Value; row <= maxCell.Row; row++)
                {
                    int colCount = 0;
                    foreach (var col in pColumnsToRead)
                    {
                        var value = worksheet.Cells[row, col].Value;
                        excelFileValues[rowCount, colCount] = Convert.ToString(value);
                        colCount++;
                    }
                    rowCount++;
                }

                return excelFileValues;
            }
        }

        /// <summary>
        /// Charge les données du fichier Excel 2003 dans un tableau
        /// </summary>
        /// <param name="pFilename">Le chemin et le nom du fichier à ouvrir</param>
        /// <param name="pStartRow">La ligne à partir de laquelle on veut exporter les données. Par défaut, la première ligne contenant des données (index 1ère ligne = 1).</param>
        /// <param name="pColumnsToRead">La liste des colonnes dont on veut extraire les données. Par défaut, toutes les colonnes (index 1ère colonne = 1.</param>
        /// <returns>Un tableau contenant les données du fichier sous forme de [lignes, colonnes]</returns>
        private static string[,] ReadXLSFileData(string pFilename, int? pStartRow = null, int[] pColumnsToRead = null)
        {
            FileStream fs = new FileStream(pFilename, FileMode.Open, FileAccess.Read);

            // Getting the complete workbook...
            using (HSSFWorkbook workbook = new HSSFWorkbook(fs, true))
            {
                ISheet worksheet = workbook.GetSheetAt(0);

                //get dimensions & default values:
                pStartRow = pStartRow.HasValue ? pStartRow : 1;
                pColumnsToRead = pColumnsToRead ?? Enumerable.Range(1, worksheet.GetRow(0).PhysicalNumberOfCells).ToArray();

                //check dimensions
                if (pStartRow < 1 || pStartRow > worksheet.PhysicalNumberOfRows || pColumnsToRead.Min() < 1 || pColumnsToRead.Max() > worksheet.GetRow(0).PhysicalNumberOfCells)
                    throw new ArgumentOutOfRangeException("");

                var excelFileValues = new string[(worksheet.LastRowNum + 1) - pStartRow.Value + 1, pColumnsToRead.Length];

                int rowCount = 0;
                for (int rowIndex = pStartRow.Value - 1; rowIndex <= worksheet.LastRowNum; rowIndex++)
                {
                    int colCount = 0;
                    var row = worksheet.GetRow(rowIndex);
                    foreach (var col in pColumnsToRead)
                    {
                        var cell = row.GetCell(col - 1);

                        //si la cellule est vide, cell peut être null
                        if (cell != null)
                        {
                            //bidouille parce que NPOI est nul et considère les cellules contenant des nombres comme numérique
                            cell.SetCellType(CellType.STRING);
                            excelFileValues[rowCount, colCount] = cell.StringCellValue;
                        }
                        else
                        {
                            excelFileValues[rowCount, colCount] = null;
                        }
                        colCount++;
                    }
                    rowCount++;
                }

                return excelFileValues;
            }
        }

        /// <summary>
        /// Ecrit les données dans un fichier 2007.
        /// </summary>
        /// <param name="pFilename">Le chemin et le nom du fichier à créer</param>
        /// <param name="pData">Un tableau contenant les données du fichier sous forme de [lignes, colonnes]</param>
        private static void WriteXLSXFileData(string pFilename, string[,] pData)
        {
            FileInfo fi = new FileInfo(pFilename);

            using (ExcelPackage xlPackage = new ExcelPackage(fi))
            {
                var worksheet = xlPackage.Workbook.Worksheets.Add("Log");

                for (int row = pData.GetLowerBound(0); row <= pData.GetUpperBound(0); row++)
                {
                    for (int col = pData.GetLowerBound(1); col <= pData.GetUpperBound(1); col++)
                        worksheet.Cells[row + 1, col + 1].Value = pData[row, col];
                }
                xlPackage.Save();
            }
        }
    }
}
